{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# default_exp models.MLP"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MLP\n",
    "\n",
    "> This is an unofficial PyTorch implementation by Ignacio Oguiza (oguiza@gmail.com) based on **Fawaz, H. I., Forestier, G., Weber, J., Idoumghar, L., & Muller, P. A. (2019). Deep learning for time series classification: a review. Data Mining and Knowledge Discovery, 33(4), 917-963.** Official MLP TensorFlow implementation in https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/mlp.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "from tsai.imports import *\n",
    "from tsai.models.layers import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#export\n",
    "class MLP(Module):\n",
    "    def __init__(self, c_in, c_out, seq_len, layers=[500,500,500], ps=[0.1, 0.2, 0.2], act=nn.ReLU(inplace=True),\n",
    "                 use_bn=False, bn_final=False, lin_first=False, fc_dropout=0., y_range=None):\n",
    "        layers, ps = L(layers), L(ps)\n",
    "        if len(ps) <= 1: ps = ps * len(layers)\n",
    "        assert len(layers) == len(ps), '#layers and #ps must match'\n",
    "        self.flatten = Reshape(-1)\n",
    "        nf = [c_in * seq_len] + layers\n",
    "        self.mlp = nn.ModuleList()\n",
    "        for i in range(len(layers)): self.mlp.append(LinBnDrop(nf[i], nf[i+1], bn=use_bn, p=ps[i], act=get_act_fn(act), lin_first=lin_first))\n",
    "        _head = [LinBnDrop(nf[-1], c_out, bn=bn_final, p=fc_dropout)]\n",
    "        if y_range is not None: _head.append(SigmoidRange(*y_range))\n",
    "        self.head = nn.Sequential(*_head)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.flatten(x)\n",
    "        for mlp in self.mlp: x = mlp(x)\n",
    "        return self.head(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MLP(\n",
       "  (flatten): Reshape(bs, -1)\n",
       "  (mlp): ModuleList(\n",
       "    (0): LinBnDrop(\n",
       "      (0): Dropout(p=0.1, inplace=False)\n",
       "      (1): Linear(in_features=384, out_features=500, bias=True)\n",
       "      (2): ReLU(inplace=True)\n",
       "    )\n",
       "    (1): LinBnDrop(\n",
       "      (0): Dropout(p=0.2, inplace=False)\n",
       "      (1): Linear(in_features=500, out_features=500, bias=True)\n",
       "      (2): ReLU(inplace=True)\n",
       "    )\n",
       "    (2): LinBnDrop(\n",
       "      (0): Dropout(p=0.2, inplace=False)\n",
       "      (1): Linear(in_features=500, out_features=500, bias=True)\n",
       "      (2): ReLU(inplace=True)\n",
       "    )\n",
       "  )\n",
       "  (head): Sequential(\n",
       "    (0): LinBnDrop(\n",
       "      (0): Linear(in_features=500, out_features=2, bias=True)\n",
       "    )\n",
       "  )\n",
       ")"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bs = 16\n",
    "nvars = 3\n",
    "seq_len = 128\n",
    "c_out = 2\n",
    "xb = torch.rand(bs, nvars, seq_len)\n",
    "model = MLP(nvars, c_out, seq_len)\n",
    "test_eq(model(xb).shape, (bs, c_out))\n",
    "model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#hide\n",
    "out = create_scripts()\n",
    "beep(out)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
